package guru.mercurio.core.ws;

import electric.glue.context.ThreadContext;
import guru.mercurio.common.PhoneAddress;
import guru.mercurio.common.RelativeApplicationAddress;
import guru.mercurio.common.Status;
import guru.mercurio.core.MercurioAntiFlood;
import guru.mercurio.core.PassportManager;
import guru.mercurio.data.ChannelDataManager;
import guru.mercurio.data.DataManager;
import guru.mercurio.data.PassportDataManager;
import guru.merlin.core.AddressException;
import guru.merlin.core.Envelope;
import guru.merlin.core.EnvelopeHandler;
import guru.merlin.core.EnvelopeProcessor;
import guru.util.EMailer;
import java.util.Properties;

import org.apache.log4j.Logger;

public class Mercurio implements guru.mercurio.core.ws.MercurioI{
    static Logger logger = Logger.getLogger(Mercurio.class);
    
    private EnvelopeHandler handler;
    private ChannelDataManager cdm;
    private PassportDataManager pdm;
    private PassportManager passManager;
    public Properties properties;
    
    public Mercurio(EnvelopeProcessor p, DataManager dm, Properties properties) throws Exception {
        
        passManager = new PassportManager(dm);
        pdm = new PassportDataManager(dm);
        cdm = new ChannelDataManager(dm);
        
        if ((handler = p.getEnvelopeHandler()) == null) { throw new Exception("EnvelopeHandler not seted in Mercurios EnvelopeProcessor"); }
        this.properties=properties;
    }
    
    // Compatibilidad v1.x
    // *************************************************************************
    public int configurarURLReceptorSMS(String pasaporte, String password, String url, String llave) {
        return (configurarAplicacion(pasaporte, password, "cgi", url, llave));
    }
    
    public int recibirSMS(String pasaporte, String password) {
        return (iniciarRecepcion(pasaporte, password));
    }
    
    // Implementacion
    // *************************************************************************
    public int enviarSMS(String pasaporte, String password, String codPaisDest, String codAreaDest, String numeroDest, String mensaje) {
        if (pasaporte == null || password == null) { return Status.PASAPORTE_O_PASSWORD_NULOS; }
        return (responderSMS(pasaporte, password, codPaisDest, codAreaDest, numeroDest, mensaje, null));
    }
    
    public int responderSMS(String pasaporte, String password, String codPaisDest, String codAreaDest, String numeroDest, String mensaje, String idMensaje) {
        try {
            int country = new Integer(codPaisDest).intValue();
            int area = 0;
            
            if (codPaisDest.equals("58")) {
                if (numeroDest.length()!=7){
                    return Status.ERROR_NUMERO_SUMINISTRADO;
                }
                area = new Integer(codAreaDest).intValue();
            }
            
            if (codPaisDest.equals("507")) {
                if (numeroDest.length()<7 || numeroDest.length()>8){
                    return Status.ERROR_NUMERO_SUMINISTRADO;
                }
                
                int startlocal = Integer.parseInt(numeroDest.substring(0, 3));
                if (startlocal >= 656 && startlocal <= 664) {//CDMA/TDMA (078)
                    
                } else if ((startlocal == 648)|| (startlocal == 647)  || (startlocal == 649)) {//GSM (152)
                    int startlocal2 = Integer.parseInt(numeroDest.substring(0, 4));
                    if ((startlocal2 >= 6480 && startlocal2 <= 6489) || startlocal2 == 6471 || startlocal2 <= 6491) {//GSM (152)
                        
                    }
                } else if ((startlocal >= 650 && startlocal <= 653) || (startlocal >= 665 && startlocal <= 6672)) {//Cable&Wireless(117)
                    
                } else {
                    return Status.ERROR_NUMERO_SUMINISTRADO;
                }
            }
            
            for (int v = 0; v < numeroDest.length(); v++ ){
                char c = numeroDest.charAt(v);
                if (!Character.isDigit(c)){
                    return Status.ERROR_NUMERO_SUMINISTRADO;
                }
            }
            
            int number = new Integer(numeroDest).intValue();
            
            return (responderSMS(pasaporte, password, country, area, number, mensaje, idMensaje));
        } catch (Exception e) {
            return (Status.ERROR_NUMERO_SUMINISTRADO);
        }
    }
    
    /*
     * public void responderSMS(int codPaisDest, int codAreaDest, int numeroDest, String mensaje,
     * String idMensaje){
     *  }
     */
    
    private int responderSMS(String pasaporte, String password, int codPaisDest, int codAreaDest, int numeroDest, String mensaje, String idMensaje) {
        String msg = "";
        Envelope env;
        RelativeApplicationAddress sender;
        try {
            if(logger.isDebugEnabled()) {
                logger.debug("it is going to respond SMS ");
            }
            int balance;
            int credit;
            
            mensaje = mensaje.trim();
            
            try {
                if (!passManager.authenticatePassport(pasaporte, password)) {
                    logger.warn("Not authenticated for pasaporte"+ pasaporte);
                    return (Status.NO_AUTENTICADO);
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                logger.warn("Not authenticated ");
                return (Status.NO_AUTENTICADO);
            }
            
            // AL DESCOMENTAR ESTO SE SALTA DEL v2.1.7 al v2.2.0
            balance = pdm.getBalance(pasaporte);
            credit = pdm.getCredit(pasaporte);
            
            if (balance + credit <= 0) {
                logger.warn("There isn't sufficient balance and credit");
                return (Status.SIN_SUFICIENTE_SALDO_O_CREDITO);
            }
            
            //Incorporado por Santiago Ventura, para prevenir la inundacion de mensajes desde algun
            // cliente. 20/02/2006
            MercurioAntiFlood merAntiFlood = new MercurioAntiFlood(this.properties);
            if (merAntiFlood.isAFlood(pdm,pasaporte,codPaisDest,codAreaDest,numeroDest)) {
                logger.warn("Activated Antiflood, is going away to reject the message to prevent a possible flood.");
                return (Status.FLOOD_POR_PASAPORTE_DETECTADO);
            } //Fin
            
            PhoneAddress rec = new PhoneAddress(codPaisDest, codAreaDest, numeroDest);
            
            try {
                sender = cdm.getRelativeApplicationByPassport(pasaporte, codPaisDest, codAreaDest);
            } catch (ArrayIndexOutOfBoundsException e) {
                logger.info("", e);
                e.printStackTrace();
                return (Status.DESTINO_NO_ACEPTADO);
            }
            
            sender.setPassport(pasaporte);
            
            boolean completo = false;
            while (!(completo)) {
                if (mensaje.length() > 139) {
                    env = new Envelope(mensaje.substring(0, 139), rec, sender);
                    env.setReplyTo(idMensaje);
                    handler.handEnvelope(env);
                    mensaje = mensaje.substring(139);
                } else {
                    env = new Envelope(mensaje, rec, sender);
                    env.setReplyTo(idMensaje);
                    handler.handEnvelope(env);
                    completo = true;
                }
            }
            
            // AL DESCOMENTAR ESTO SE SALTA DEL v2.1.7 al v2.2.0
            pdm.setBalance(pasaporte, balance - 1);
            
            return (Status.EXITO);
        } catch (AddressException paex) {
            return (Status.NUMERO_NO_SOPORTADO);
        } catch (Throwable t) {
            StringBuffer sb = new StringBuffer();
            sb.append("Se genero un: " + t + "\n");
            sb.append("Enviando al: +" + codPaisDest + codAreaDest + numeroDest + "\n");
            sb.append("Usando el pasaporte: " + pasaporte + "\n");
            sb.append("Stacktrace:\n");
            StackTraceElement ste[] = t.getStackTrace();
            for (int d = 0; d < ste.length; d++) {
                sb.append(ste[d].toString() + "\n");
            }
            
            EMailer.sendmail("mercurio@twindivision.com", "soporte@twindivision.com", "Error Interno @" + pasaporte, sb.toString());
            logger.error("Error Interno: pasaporte: " + pasaporte + ": " + sb.toString(), t);
            return (Status.ERROR_INTERNO);
        } finally{
            
        }
    }
    
    public int configurarAplicacion(String pasaporte, String password, String protocolo, String url, String llave) {
        return (passManager.configureApplication(pasaporte, password, protocolo, url, llave));
    }
    
    public int iniciarRecepcion(String pasaporte, String password) {
        return (passManager.startReception(pasaporte, password));
    }
    
    public int pararRecepcion(String pasaporte, String password) {
        return (passManager.stopReception(pasaporte, password));
    }
    
    // ************************************************************************
    private String getIp() {
        return ThreadContext.getHttpRequest().getRemoteAddr();
    }
}